{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/advance/functional-programing/intro.html\n",
    "\n",
    "主要关注的是函数式特性：\n",
    "\n",
    "- 闭包 Closure\n",
    "- 迭代器 Iterator\n",
    "- 模式匹配\n",
    "- 枚举"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 闭包 Closure\n",
    "\n",
    "- https://course.rs/advance/functional-programing/closure.html\n",
    "- https://practice-zh.course.rs/functional-programing/closure.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/functional-programing/closure.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TL;DR：Rust 闭包（Closure）\n",
    "\n",
    "- **闭包定义**：匿名函数，可赋值给变量、作为参数传递，并可捕获调用者作用域中的值。\n",
    "- **语法形式**：`|param1, param2| expr`，参数与返回值类型通常可省略，由编译器推导。\n",
    "- **类型推导限制**：闭包一旦推导出某种参数类型，就不能再用不同类型调用它。\n",
    "- **闭包 vs 函数**：与具名函数不同，闭包能捕获环境中的变量，并可能产生额外内存分配。\n",
    "- **三种捕获方式**：\n",
    "  - `Fn`：不可变借用捕获。\n",
    "  - `FnMut`：可变借用捕获，需要 `mut` 绑定。\n",
    "  - `FnOnce`：获取所有权，只能调用一次；`move` 强制所有权转移。\n",
    "- **闭包类型系统**：闭包自动至少实现 `FnOnce`；若不转移所有权则实现 `FnMut`；若只读捕获变量则实现 `Fn`。\n",
    "- **结构体中的闭包**：使用泛型 + `Fn*` trait 约束，因为每个闭包都有独特类型。\n",
    "- **缓存示例**：`Cacher<T: Fn(u32) -> u32>` 可存储闭包并延迟计算，但需用泛型扩展以支持更多类型。\n",
    "- **闭包作为返回值**：\n",
    "  - `-> impl Fn(...)` 适合返回单一闭包类型。\n",
    "  - 分支返回不同闭包时需使用特征对象 `Box<dyn Fn(...)>`.\n",
    "- **生命周期与 move**：闭包寿命可能长于捕获的变量，使用 `move` 将值转移避免借用问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "闭包的形式定义"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "|param1, param2,...| {\n",
    "    语句1;\n",
    "    语句2;\n",
    "    返回表达式 // 闭包中最后一行表达式返回的值，就是闭包执行后的返回值\n",
    "}"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "|param1| 返回表达式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let x = 1;\n",
    "    let sum = |y| x + y; // 可以赋值给变量，允许捕获调用者作用域中的值。\n",
    "\n",
    "    assert_eq!(3, sum(2));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用闭包来简化代码"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 传统函数实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::thread;\n",
    "use std::time::Duration;\n",
    "\n",
    "// 开始健身，好累，我得发出声音：muuuu...\n",
    "fn muuuuu(intensity: u32) -> u32 {\n",
    "    println!(\"muuuu.....\");\n",
    "    thread::sleep(Duration::from_secs(2));\n",
    "    intensity\n",
    "}\n",
    "\n",
    "fn workout(intensity: u32, random_number: u32) {\n",
    "    if intensity < 25 {\n",
    "        println!(\n",
    "            \"今天活力满满，先做 {} 个俯卧撑!\",\n",
    "            muuuuu(intensity)\n",
    "        );\n",
    "        println!(\n",
    "            \"旁边有妹子在看，俯卧撑太low，再来 {} 组卧推!\",\n",
    "            muuuuu(intensity)\n",
    "        );\n",
    "    } else if random_number == 3 {\n",
    "        println!(\"昨天练过度了，今天还是休息下吧！\");\n",
    "    } else {\n",
    "        println!(\n",
    "            \"昨天练过度了，今天干干有氧，跑步 {} 分钟!\",\n",
    "            muuuuu(intensity)\n",
    "        );\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    // 强度\n",
    "    let intensity = 10;\n",
    "    // 随机值用来决定某个选择\n",
    "    let random_number = 7;\n",
    "\n",
    "    // 开始健身\n",
    "    workout(intensity, random_number);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数变量实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::thread;\n",
    "use std::time::Duration;\n",
    "\n",
    "// 开始健身，好累，我得发出声音：muuuu...\n",
    "fn muuuuu(intensity: u32) -> u32 {\n",
    "    println!(\"muuuu.....\");\n",
    "    thread::sleep(Duration::from_secs(2));\n",
    "    intensity\n",
    "}\n",
    "\n",
    "fn workout(intensity: u32, random_number: u32) {\n",
    "    let action = muuuuu; // 把函数赋值给一个变量，然后通过变量调用\n",
    "    if intensity < 25 {\n",
    "        println!(\n",
    "            \"今天活力满满, 先做 {} 个俯卧撑!\",\n",
    "            action(intensity)\n",
    "        );\n",
    "        println!(\n",
    "            \"旁边有妹子在看，俯卧撑太low, 再来 {} 组卧推!\",\n",
    "            action(intensity)\n",
    "        );\n",
    "    } else if random_number == 3 {\n",
    "        println!(\"昨天练过度了，今天还是休息下吧！\");\n",
    "    } else {\n",
    "        println!(\n",
    "            \"昨天练过度了，今天干干有氧, 跑步 {} 分钟!\",\n",
    "            action(intensity)\n",
    "        );\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    // 强度\n",
    "    let intensity = 10;\n",
    "    // 随机值用来决定某个选择\n",
    "    let random_number = 7;\n",
    "\n",
    "    // 开始健身\n",
    "    workout(intensity, random_number);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 闭包实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::thread;\n",
    "use std::time::Duration;\n",
    "\n",
    "fn workout(intensity: u32, random_number: u32) {\n",
    "    let action = || {\n",
    "        println!(\"muuuu.....\");\n",
    "        thread::sleep(Duration::from_secs(2));\n",
    "        intensity\n",
    "    };\n",
    "\n",
    "    if intensity < 25 {\n",
    "        println!(\n",
    "            \"今天活力满满，先做 {} 个俯卧撑!\",\n",
    "            action()\n",
    "        );\n",
    "        println!(\n",
    "            \"旁边有妹子在看，俯卧撑太low，再来 {} 组卧推!\",\n",
    "            action()\n",
    "        );\n",
    "    } else if random_number == 3 {\n",
    "        println!(\"昨天练过度了，今天还是休息下吧！\");\n",
    "    } else {\n",
    "        println!(\n",
    "            \"昨天练过度了，今天干干有氧，跑步 {} 分钟!\",\n",
    "            action()\n",
    "        );\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    // 动作次数\n",
    "    let intensity = 10;\n",
    "    // 随机值用来决定某个选择\n",
    "    let random_number = 7;\n",
    "\n",
    "    // 开始健身\n",
    "    workout(intensity, random_number);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 闭包的类型推导"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 函数: 必须手动为函数的所有参数和返回值指定类型，原因在于函数往往会作为 API 提供给你的用户，因此你的用户必须在使用时知道传入参数的类型和返回值类型。\n",
    "- 闭包: 闭包并不会作为 API 对外提供，因此它可以享受编译器的类型推导能力，无需标注参数和返回值的类型. 为了增加代码可读性，有时候我们会显式地给类型进行标注，出于同样的目的，也可以给闭包标注类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let sum = |x: i32, y: i32| -> i32 {\n",
    "    x + y\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let sum  = |x, y| x + y;\n",
    "let v = sum(1, 2);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "type annotations needed",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0284] Error:\u001b[0m type annotations needed",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_12:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m+\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;100m┬\u001b[0m\u001b[38;5;68m│\u001b[0m                 \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m error: type annotations needed",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;68m│\u001b[0m                 \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider giving this closure parameter an explicit type: `: /* Type */`",
      " \u001b[38;5;240m  │\u001b[0m                                      \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                      \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m type must be known at this point",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn  add_one_v1   (x: u32) -> u32 { x + 1 }\n",
    "let add_one_v2 = |x: u32| -> u32 { x + 1 };\n",
    "let add_one_v3 = |x|             { x + 1 };"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "type annotations needed",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0284] Error:\u001b[0m type annotations needed",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_11:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m+\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;100m┬\u001b[0m\u001b[38;5;68m│\u001b[0m                 \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m error: type annotations needed",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;68m│\u001b[0m                 \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider giving this closure parameter an explicit type: `: /* Type */`",
      " \u001b[38;5;240m  │\u001b[0m                                      \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                      \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m type must be known at this point",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let add_one_v4 = |x|               x + 1  ;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let example_closure = |x| x;\n",
    "\n",
    "let s = example_closure(String::from(\"hello\"));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot find function `example_closure` in this scope",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0425] Error:\u001b[0m cannot find function `example_closure` in this scope",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_14:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let n = example_closure(5); // 虽然类型推导很好用，但是它不是泛型，当编译器推导出一种类型后，它就会一直使用该类型："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结构体中的闭包"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实现一个简易缓存，功能是获取一个值，然后将其缓存起来:\n",
    "- 一个闭包用于获取值\n",
    "- 一个变量，用于存储该值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "struct Cacher<T>\n",
    "where\n",
    "    T: Fn(u32) -> u32, // 该闭包拥有一个u32类型的参数，同时返回一个u32类型的值。\n",
    "{\n",
    "    query: T,\n",
    "    value: Option<u32>,\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "impl<T> Cacher<T>\n",
    "where\n",
    "    T: Fn(u32) -> u32,\n",
    "{\n",
    "    fn new(query: T) -> Cacher<T> {\n",
    "        Cacher {\n",
    "            query,\n",
    "            value: None,\n",
    "        }\n",
    "    }\n",
    "\n",
    "    // 先查询缓存值 `self.value`，若不存在，则调用 `query` 加载\n",
    "    fn value(&mut self, arg: u32) -> u32 {\n",
    "        match self.value {\n",
    "            Some(v) => v,\n",
    "            None => {\n",
    "                let v = (self.query)(arg);\n",
    "                self.value = Some(v);\n",
    "                v\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的缓存有一个很大的问题：只支持 `u32` 类型的值，若我们想要缓存 `&str` 类型，显然就行不通了，因此需要将 `u32` 替换成泛型 `E`，该练习就留给读者自己完成，具体代码可以参考[这里](https://practice-zh.course.rs/functional-programing/closure.html#closure-in-structs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 捕获作用域中的值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TL;DR\n",
    "\n",
    "- 闭包能捕获所在作用域的变量，函数不能；捕获方式对应 Rust 的三种借用/所有权模式。\n",
    "- 闭包总是至少实现 `FnOnce`；若未夺取所有权则实现 `FnMut`；若只是读借用则实现 `Fn`。\n",
    "- `move` 仅决定捕获方式，不影响闭包还能否实现 `Fn`/`FnMut`。\n",
    "- 是否需要 `mut` 取决于调用时是否修改闭包内部状态，与闭包推导出的 `Fn*` 特征无直接关系。\n",
    "- 闭包能否 `Copy` 取决于所捕获值能否 `Copy`；编译器报错提示会指导选择合适的 `Fn*` 约束。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 闭包捕获环境的能力\n",
    "\n",
    "- 闭包可以“记住”其定义时所在作用域的变量，函数则不行。\n",
    "- 捕获方式与所有权/借用一致：取得所有权、可变借用、不可变借用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let x = 4;\n",
    "\n",
    "    let equal_to_x = |z| z == x;\n",
    "\n",
    "    let y = 4;\n",
    "\n",
    "    assert!(equal_to_x(y));\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "can't capture dynamic environment in a fn item",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0434] Error:\u001b[0m can't capture dynamic environment in a fn item",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_18:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mz\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mx\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m error: can't capture dynamic environment in a fn item",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "unused variable: `x`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[unused_variables] Error:\u001b[0m unused variable: `x`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_18:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m warning: unused variable: `x`",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: if this is intentional, prefix it with an underscore: `_x`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let x = 4;\n",
    "\n",
    "    fn equal_to_x(z: i32) -> bool {\n",
    "        z == x\n",
    "    }\n",
    "\n",
    "    let y = 4;\n",
    "\n",
    "    assert!(equal_to_x(y));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### * 三个 Fn 系列特征的含义与关系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 特征     | 捕获方式           | 调用签名       | 备注                                   |\n",
    "| -------- | ------------------ | -------------- | -------------------------------------- |\n",
    "| `FnOnce` | 取得捕获值的所有权 | `self`（按值） | 所有闭包都至少实现它；只能保证调用一次 |\n",
    "| `FnMut`  | 可变借用捕获       | `&mut self`    | 若闭包未移出所有权，则自动实现         |\n",
    "| `Fn`     | 不可变借用捕获     | `&self`        | 若闭包只读捕获内容，则自动实现         |\n",
    "\n",
    "- `Fn` ⊂ `FnMut` ⊂ `FnOnce`，源码中可看到特征的继承链：`Fn: FnMut`，`FnMut: FnOnce`。\n",
    "- 判断闭包实现哪种特征，关键看**它如何使用**捕获的变量，而非是否使用 `move`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### `FnOnce`：夺取捕获的所有权"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "use of moved value: `func`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m use of moved value: `func`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_19:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249mF\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;68mf\u001b[0m\u001b[38;5;68mu\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mc\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mF\u001b[0m\u001b[38;5;249m)\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m move occurs because `func` has type `F`, which does not implement the `Copy` trait",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m3\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `func` moved due to this call",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mf\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mc\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value used here after move",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn fn_once<F>(func: F)\n",
    "where\n",
    "    F: FnOnce(usize) -> bool,\n",
    "{\n",
    "    println!(\"{}\", func(3));\n",
    "    println!(\"{}\", func(4));\n",
    "}\n",
    "\n",
    "{\n",
    "    let x = vec![1, 2, 3];\n",
    "    fn_once(|z|{z == x.len()})\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "false\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn fn_once<F>(func: F)\n",
    "where\n",
    "    F: FnOnce(usize) -> bool + Copy,// 改动在这里\n",
    "{\n",
    "    println!(\"{}\", func(3));\n",
    "    println!(\"{}\", func(4));\n",
    "}\n",
    "\n",
    "{\n",
    "    let x = vec![1, 2, 3];\n",
    "    fn_once(|z|{z == x.len()});\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果你想强制闭包取得捕获变量的所有权，可以在参数列表前添加 `move` 关键字，这种用法通常用于闭包的生命周期大于捕获变量的生命周期时，例如将闭包返回或移入其他线程。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Here's a vector: [1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "use std::thread;\n",
    "let v = vec![1, 2, 3];\n",
    "let handle = thread::spawn(move || {\n",
    "    println!(\"Here's a vector: {:?}\", v);\n",
    "});\n",
    "handle.join().unwrap();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### `FnMut`：可变捕获（可变借用）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot borrow `update_string` as mutable, as it is not declared as mutable",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0596] Error:\u001b[0m cannot borrow `update_string` as mutable, as it is not declared as mutable",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_26:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m│\u001b[0m                      \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider changing this to be mutable: `mut `",
      " \u001b[38;5;240m  │\u001b[0m                                \u001b[38;5;100m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m calling `update_string` requires mutable binding due to mutable borrow of `s`",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m cannot borrow as mutable",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: You can change an existing variable to mutable like: `let mut x = x;`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let mut s = String::new();\n",
    "\n",
    "    let update_string =  |str| s.push_str(str); // 想要在闭包内部捕获可变借用，需要把该闭包声明为可变类型\n",
    "    update_string(\"hello\");\n",
    "\n",
    "    println!(\"{:?}\",s);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"hello\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let mut s = String::new();\n",
    "\n",
    "    let mut update_string =  |str| s.push_str(str);\n",
    "    update_string(\"hello\");\n",
    "\n",
    "    println!(\"{:?}\",s);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"hello\"\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let mut s = String::new();\n",
    "\n",
    "    let update_string =  |str| s.push_str(str);\n",
    "\n",
    "    exec(update_string); // update_string 这个闭包值按所有权被移动到 exec 里（参数传递）。\n",
    "                         // 在 exec 函数内部，它被绑定为 mut f，于是可以以可变方式调用。\n",
    "                         // main 根本不会再调用这个闭包（因为所有权已经被移动），所以也就不需要把 update_string 声明成 mut。\n",
    "                         // 需要 mut 的，是调用闭包的地方，不是闭包定义的地方。\n",
    "    println!(\"{:?}\",s);\n",
    "}\n",
    "\n",
    "// `<'a, F: FnMut(&'a str)>`: 泛型参数列表\n",
    "//\n",
    "// `'a`: \n",
    "//  - 一个生命周期参数。出现它的原因是：闭包类型 F 需要实现 FnMut(&'a str)，也就是可以被调用，接收一个带有生命周期 'a 的字符串切片 &'a str。\n",
    "//  - 生命周期 'a 用来约束：闭包所接受的字符串引用在整个调用过程中必须保持有效。\n",
    "//\n",
    "// `F: FnMut(&'a str)`: 声明 F 是一个实现了 FnMut(&'a str) 的类型，也就是说：\n",
    "//  - F 是一个可以多次调用（需要 &mut self）的闭包或函数对象。\n",
    "//  - 每次调用时需要传入一个 &'a str 类型的参数。\n",
    "//\n",
    "// (mut f: F):\n",
    "//  - 参数模式写成 mut f，表示在函数体内会以可变方式使用这个参数（因为调用 FnMut 闭包需要 &mut self）\n",
    "fn exec<'a, F: FnMut(&'a str)>(mut f: F)  {\n",
    "    f(\"hello\")\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let update_string: impl FnMut(&str) =  |str| s.push_str(str); // rust-analyzer自动给出的类型标注"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> “谁要调用 `FnMut` 闭包，谁的手里就得有 `mut` 的绑定。”"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "所有权与 `Copy`\n",
    "\n",
    "- 闭包默认不实现 `Copy`。\n",
    "- 只要闭包捕获的每个捕获变量都实现了 `Copy`（并且是按不可变引用捕获），闭包就能自动实现 `Copy`。\n",
    "- 捕获 `String` 的所有权或可变引用显然不能 `Copy`，所以拿走一次就用完了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  let s = String::new();\n",
    "  let update_string =  || println!(\"{}\",s);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn exec<F: FnMut()>(mut f: F) {\n",
    "    f();\n",
    "}\n",
    "\n",
    "{\n",
    "  let s = String::new();\n",
    "  let update_string = move || println!(\"{}\", s); // 拿所有权\n",
    "\n",
    "  exec(update_string);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "use of moved value: `update_string`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m use of moved value: `update_string`",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_9:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m 7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mu\u001b[0m\u001b[38;5;68mp\u001b[0m\u001b[38;5;68md\u001b[0m\u001b[38;5;68ma\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68m_\u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mg\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m       \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m             \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m move occurs because `update_string` has type `{closure@src/lib.rs:27:23: 27:30}`, which does not implement the `Copy` trait",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;246m 9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m        \u001b[38;5;37m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m        \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m help: consider borrowing `update_string`: `&`",
      " \u001b[38;5;240m   │\u001b[0m              \u001b[38;5;54m│\u001b[0m        ",
      " \u001b[38;5;240m   │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value moved here",
      " \u001b[38;5;246m10 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mg\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m        \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m              \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value used here after move",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn exec<F: FnMut()>(mut f: F) {\n",
    "    f();\n",
    "}\n",
    "\n",
    "{\n",
    "  let s = String::new();\n",
    "  let update_string = move || println!(\"{}\", s);\n",
    "\n",
    "  exec(update_string);\n",
    "  exec(update_string);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn exec<F: FnMut()>(mut f: F) {\n",
    "    f();\n",
    "}\n",
    "\n",
    "{\n",
    "  let mut s = String::new();\n",
    "  let mut update_string = || s.push_str(\"hello\"); // 取得的是s的可变引用，没有实现Copy\n",
    "\n",
    "  exec(update_string);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "use of moved value: `update_string`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m use of moved value: `update_string`",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_11:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m 7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                              \u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                              \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `s` out of its environment",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;246m 9 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m        \u001b[38;5;37m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m        \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m help: consider mutably borrowing `update_string`: `&mut `",
      " \u001b[38;5;240m   │\u001b[0m              \u001b[38;5;54m│\u001b[0m        ",
      " \u001b[38;5;240m   │\u001b[0m              \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value moved here",
      " \u001b[38;5;246m10 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mg\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m        \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m              \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value used here after move",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn exec<F: FnMut()>(mut f: F) {\n",
    "    f();\n",
    "}\n",
    "\n",
    "{\n",
    "  let mut s = String::new();\n",
    "  let mut update_string = || s.push_str(\"hello\");\n",
    "\n",
    "  exec(update_string);\n",
    "  exec(update_string);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### `Fn`：只读捕获（不可变借用）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0525] Error:\u001b[0m expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_12:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m 4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m|\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54m|\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                          \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m \u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                            \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m this closure implements `FnMut`, not `Fn`",
      " \u001b[38;5;240m   │\u001b[0m                                \u001b[38;5;68m│\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                                \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m closure is `FnMut` because it mutates the variable `s` here",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;246m 6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;37me\u001b[0m\u001b[38;5;37mx\u001b[0m\u001b[38;5;37me\u001b[0m\u001b[38;5;37mc\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mp\u001b[0m\u001b[38;5;100md\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mg\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m     \u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m┬\u001b[0m\u001b[38;5;37m─\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m       \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m required by a bound introduced by this call",
      " \u001b[38;5;240m   │\u001b[0m                \u001b[38;5;100m│\u001b[0m        ",
      " \u001b[38;5;240m   │\u001b[0m                \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m the requirement to implement `Fn` derives from here",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;246m11 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m<\u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mF\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;97mF\u001b[0m\u001b[38;5;97mn\u001b[0m\u001b[38;5;97m(\u001b[0m\u001b[38;5;97m&\u001b[0m\u001b[38;5;97m'\u001b[0m\u001b[38;5;97ma\u001b[0m\u001b[38;5;97m \u001b[0m\u001b[38;5;97ms\u001b[0m\u001b[38;5;97mt\u001b[0m\u001b[38;5;97mr\u001b[0m\u001b[38;5;97m)\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mF\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                \u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m┬\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                     \u001b[38;5;97m╰\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m\u001b[38;5;97m─\u001b[0m required by this bound in `exec`",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let mut s = String::new();\n",
    "\n",
    "    let update_string =  |str| s.push_str(str); // 期望闭包实现的是`Fn`特征，但是它只实现了`FnMut`特征\n",
    "\n",
    "    exec(update_string);\n",
    "\n",
    "    println!(\"{:?}\",s);\n",
    "}\n",
    "\n",
    "fn exec<'a, F: Fn(&'a str)>(mut f: F)  {\n",
    "    f(\"hello\")\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, ,world\n",
      "\"hello, \"\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let s = \"hello, \".to_string();\n",
    "\n",
    "    let update_string =  |str| println!(\"{},{}\",s,str);\n",
    "\n",
    "    exec(update_string);\n",
    "\n",
    "    println!(\"{:?}\",s);\n",
    "}\n",
    "\n",
    "fn exec<'a, F: Fn(String) -> ()>(f: F)  {\n",
    "    f(\"world\".to_string())\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### move 和 Fn"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 捕获方式                                                     | 闭包体的行为     | 实现的特征                          |\n",
    "| ------------------------------------------------------------ | ---------------- | ----------------------------------- |\n",
    "| `move` + **只读**使用捕获值（例如 `println!(\"{}\", s)` 只借用 `s`） | 只需 `&self`     | `Fn` → 也自动实现 `FnMut`、`FnOnce` |\n",
    "| `move` + **可变**使用捕获值（例如 `s.push_str(...)`）        | 需要 `&mut self` | `FnMut` → 同时是 `FnOnce`           |\n",
    "| `move` + **移动/消费**捕获值（例如 `drop(s)`、`return s`）   | 必须拿走 `self`  | 仅 `FnOnce`                         |\n",
    "\n",
    "关键点：`move` 决定“闭包把环境怎么带进来”；`Fn / FnMut / FnOnce` 决定“调用闭包时需要什么权限”。这两件事是独立的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "{\n",
    "    let s = String::new();\n",
    "\n",
    "    let update_string =  move || println!(\"{}\",s);\n",
    "\n",
    "    exec(update_string);\n",
    "}\n",
    "\n",
    "fn exec<F: FnOnce()>(f: F)  {\n",
    "    f()\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `move` 让 `s` 的所有权转移到闭包内部，闭包环境本质上是一个结构体字段 `s: String`。\n",
    "- `println!(\"{}\", s)` 并没有把 `s` 再次移动出去，只是临时借用了 `&s` 来格式化输出。\n",
    "- 因此，每次调用闭包都只需要对闭包自身做共享借用（`&self`），编译器就把这个闭包实现为 `Fn`。\n",
    "\n",
    "由于 trait 继承关系：`Fn` ⊂ `FnMut` ⊂ `FnOnce`，实现了 `Fn` 的闭包自然也满足 `FnMut` 和 `FnOnce` 的约束。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`move` 关键字的作用只有一个：**它改变闭包捕获变量的方式——从默认的借用，改为按值（所有权）捕获**。这意味着：\n",
    "\n",
    "- 默认情况下，闭包会尽量使用 **借用**（不可变或可变）来捕获外部变量。\n",
    "- 加上 `move` 后，闭包会把这些变量 **按值搬进闭包环境**，即闭包拥有它们的所有权。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 三种 Fn 的关系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 条件                                            | 闭包类型                  | 可被约束为 |\n",
    "| ----------------------------------------------- | ------------------------- | ---------- |\n",
    "| 所有闭包至少可以 **调用一次**                   | `FnOnce`                  | ✅          |\n",
    "| 闭包调用时 **不把捕获的值移出**（只借用或修改） | `FnOnce` + `FnMut`        | ✅          |\n",
    "| 闭包调用时 **既不移出也不修改** 捕获的值        | `FnOnce` + `FnMut` + `Fn` | ✅          |\n",
    "\n",
    "换句话说：\n",
    "- `Fn` ⊂ `FnMut` ⊂ `FnOnce`\n",
    "- 实现了更“严格”特征的闭包，必然也实现了更“宽松”的那个。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 同一个闭包满足三种特征\n",
    "\n",
    "{\n",
    "    let s = String::new();\n",
    "\n",
    "    let update_string = || println!(\"{}\", s); // 只做只读借用. 在闭包体调用 println! 时，宏内部只会对 s 做一次 共享借用（&s），用于格式化输出\n",
    "\n",
    "    exec(update_string);  // FnOnce\n",
    "    exec1(update_string); // FnMut\n",
    "    exec2(update_string); // Fn\n",
    "}\n",
    "\n",
    "fn exec<F: FnOnce()>(f: F)        { f() }\n",
    "fn exec1<F: FnMut()>(mut f: F)    { f() }\n",
    "fn exec2<F: Fn()>(f: F)           { f() }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 闭包把捕获值移出 ⇒ 只能是 FnOnce\n",
    "\n",
    "{\n",
    "    let mut s = String::new();\n",
    "\n",
    "    let update_string = |str| -> String { s.push_str(str); s };\n",
    "\n",
    "    exec(update_string);\n",
    "}\n",
    "\n",
    "fn exec<'a, F: FnOnce(&'a str) -> String>(mut f: F) {\n",
    "    f(\"hello\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "实际建议\n",
    "\n",
    "1. **默认用 `Fn` 约束**：最严格，最“安全”；编译报错再放宽到 `FnMut` 或 `FnOnce`。\n",
    "2. 记住：`move` 只影响捕获方式（按值/按引用），**特征实现要看闭包调用时对捕获值的用法**。\n",
    "3. 如果闭包要多次调用并保留状态，确保你给它的 trait 约束允许可变借用（`FnMut`）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Trait 源码（简化版）再次佐证**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "pub trait Fn<Args>: FnMut<Args> { /* takes &self */ }\n",
    "pub trait FnMut<Args>: FnOnce<Args> { /* takes &mut self */ }\n",
    "pub trait FnOnce<Args> {\n",
    "    type Output;\n",
    "    /* takes self */\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `Fn` 继承 `FnMut`，`FnMut` 又继承 `FnOnce`。\n",
    "- `Fn` 调用需要 `&self`，`FnMut` 需要 `&mut self`，`FnOnce` 消费 `self`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 闭包作为函数返回值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **直接写 `Fn(...) -> ...` 作为返回值类型不行**：闭包的真实类型是匿名且编译期未知尺寸的，不能直接当作返回值。\n",
    "- **`impl Trait` 适合“单一具体闭包类型”**：用 `fn factory() -> impl Fn(i32) -> i32` 返回闭包，如果所有返回路径都产生同一个闭包类型（例如同一个 `move |x| ...`），编译器能推断出具体类型，返回是安全的。\n",
    "- **需要返回“多种闭包类型”时就得装箱**：分支里产生的闭包类型不同，即便签名一样，也会报错；这时用 `Box<dyn Fn(...) -> ...>` 做特征对象，将闭包放进堆里返回。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "expected a type, found a trait",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0782] Error:\u001b[0m expected a type, found a trait",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_19:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mF\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54m3\u001b[0m\u001b[38;5;54m2\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m-\u001b[0m\u001b[38;5;54m>\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54m3\u001b[0m\u001b[38;5;54m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;100m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m help: use `impl Fn(i32) -> i32` to return an opaque type, as long as you return a single underlying type: `impl `",
      " \u001b[38;5;240m  │\u001b[0m                        \u001b[38;5;54m│\u001b[0m        ",
      " \u001b[38;5;240m  │\u001b[0m                        \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m error: expected a type, found a trait",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn factory() -> Fn(i32) -> i32 {\n",
    "    let num = 5;\n",
    "\n",
    "    |x| x + num\n",
    "}\n",
    "\n",
    "let f = factory();\n",
    "\n",
    "let answer = f(1);\n",
    "assert_eq!(6, answer);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在[特征](https://course.rs/basic/trait/trait.html)那一章，我们提到过，`impl Trait` 的返回方式有一个非常大的局限，就是你只能返回同样的类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`if` and `else` have incompatible types",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0308] Error:\u001b[0m `if` and `else` have incompatible types",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_20:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m5 │\u001b[0m \u001b[38;5;37m╭\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m▶\u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;37mi\u001b[0m\u001b[38;5;37mf\u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37mx\u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m>\u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m1\u001b[0m\u001b[38;5;37m{\u001b[0m",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;37m│\u001b[0m   \u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54m|\u001b[0m\u001b[38;5;54mx\u001b[0m\u001b[38;5;54m|\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68mx\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68m+\u001b[0m\u001b[38;5;68m \u001b[0m\u001b[38;5;68mn\u001b[0m\u001b[38;5;68mu\u001b[0m\u001b[38;5;68mm\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;37m│\u001b[0m           \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;37m│\u001b[0m               \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m the expected closure",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;37m│\u001b[0m                   \u001b[38;5;68m│\u001b[0m         ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;37m│\u001b[0m                   \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m expected because of this",
      " \u001b[38;5;240m  ┆\u001b[0m \u001b[38;5;37m┆\u001b[0m   ",
      " \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;37m│\u001b[0m   \u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mv\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m|\u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;100m|\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100mx\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100m-\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100mn\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mm\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;37m│\u001b[0m           \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;37m│\u001b[0m                   \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m expected closure, found a different closure",
      " \u001b[38;5;246m9 │\u001b[0m \u001b[38;5;37m├\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m▶\u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m \u001b[0m\u001b[38;5;37m}\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;37m│\u001b[0m           ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m `if` and `else` have incompatible types",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// https://godbolt.org/z/dfdP63Eh3\n",
    "\n",
    "fn factory(x:i32) -> impl Fn(i32) -> i32 {\n",
    "\n",
    "    let num = 5;\n",
    "\n",
    "    if x > 1{\n",
    "        move |x| x + num\n",
    "    } else {\n",
    "        move |x| x - num\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "本章节前面咱们有提到：就算签名一样的闭包，类型也是不同的，因此在这种情况下，就无法再使用 `impl Trait` 的方式去返回闭包。"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "error[E0308]: `if` and `else` have incompatible types\n",
    "  --> <source>:11:9\n",
    "   |\n",
    " 8 | /     if x > 1{\n",
    " 9 | |         move |x| x + num\n",
    "   | |         ----------------\n",
    "   | |         |\n",
    "   | |         the expected closure\n",
    "   | |         expected because of this\n",
    "10 | |     } else {\n",
    "11 | |         move |x| x - num\n",
    "   | |         ^^^^^^^^^^^^^^^^ expected closure, found a different closure\n",
    "12 | |     }\n",
    "   | |_____- `if` and `else` have incompatible types\n",
    "   |\n",
    "   = note: expected closure `{closure@<source>:9:9: 9:17}`\n",
    "              found closure `{closure@<source>:11:9: 11:17}`\n",
    "   = note: no two closures, even if identical, have the same type\n",
    "   = help: consider boxing your closure and/or using it as a trait object\n",
    "help: you could change the return type to be a boxed trait object\n",
    "   |\n",
    " 4 - fn factory(x:i32) -> impl Fn(i32) -> i32 {\n",
    " 4 + fn factory(x:i32) -> Box<dyn Fn(i32) -> i32> {\n",
    "   |\n",
    "help: if you change the return type to expect trait objects, box the returned expressions\n",
    "   |\n",
    " 9 ~         Box::new(move |x| x + num)\n",
    "10 |     } else {\n",
    "11 ~         Box::new(move |x| x - num)\n",
    "   |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以用特征对象！只需要用 `Box` 的方式即可实现："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn factory(x:i32) -> Box<dyn Fn(i32) -> i32> {\n",
    "    let num = 5;\n",
    "\n",
    "    if x > 1{\n",
    "        Box::new(move |x| x + num)\n",
    "    } else {\n",
    "        Box::new(move |x| x - num)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [闭包的生命周期](https://course.rs/advance/functional-programing/closure.html#闭包的生命周期)\n",
    "\n",
    "这块儿内容在进阶生命周期章节中有讲，这里就不再赘述，读者可移步[此处](https://course.rs/advance/lifetime/advance.html#闭包函数的消除规则)进行回顾。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 迭代器 Iterator\n",
    "\n",
    "- https://course.rs/advance/functional-programing/iterator.html\n",
    "\n",
    "**迭代器是遍历抽象**：替你处理起止、索引等细节，专注元素如何处理。`for` 循环其实只是语法糖，底层连续调用迭代器的 `next`.\n",
    "\n",
    "**惰性执行**：迭代器不会主动干活；直到 `for`、`sum`、`collect` 等消费者触发，才真正遍历元素。\n",
    "\n",
    "**核心特征**：实现 `Iterator` 的类型需提供 `next`；实现 `IntoIterator` 的集合可转换为迭代器（例如数组、`Vec`、范围）。\n",
    "\n",
    "**所有权三兄弟**：\n",
    "\n",
    "- `into_iter()`：拿走所有权。\n",
    "- `iter()`：不可变借用，`next` 返回 `&T`.\n",
    "- `iter_mut()`：可变借用，`next` 返回 `&mut T`.\n",
    "\n",
    "**消费者 vs. 适配器**：\n",
    "\n",
    "- 消费者（`sum`、`collect`、`fold` 等）会耗尽迭代器并返回值。\n",
    "- 迭代器适配器（`map`、`filter`、`zip`、`enumerate` 等）返回新迭代器，可链式调用，但仍惰性，需最终消费者收尾。\n",
    "\n",
    "**闭包加持**：适配器常用闭包处理元素，可捕获外部环境值（如 `filter(|s| s.size == shoe_size)`）。\n",
    "\n",
    "**自定义迭代器**：为自定义类型实现 `Iterator` 的 `next`（默认实现都基于它）；即可与标准适配器、消费者无缝协作。\n",
    "\n",
    "**性能无损**：编译器可做循环展开、向量化等优化；迭代器属零成本抽象，速度媲美手写循环。\n",
    "\n",
    "**多看标准库**：迭代器方法繁多，掌握常用接口，才能写出简洁高效的 Rust 代码。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## For 循环与迭代器\n",
    "\n",
    "- Rust 的 `for` 循环只是语法糖：内部自动把可迭代的东西转成迭代器并调用 `next`.\n",
    "- 与需要显式索引的传统循环不同，Rust 直接遍历元素，免去起止与索引控制。\n",
    "- 迭代器赋予 Rust 函数式风格的强大表达力，远胜基础循环。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "//  JS 代码\n",
    "\n",
    "let arr = [1, 2, 3];\n",
    "for (let i = 0; i < arr.length; i++) {\n",
    "  console.log(arr[i]);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let arr = [1, 2, 3];\n",
    "for v in arr {\n",
    "    println!(\"{}\",v);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 数组本身不是迭代器，但实现了 `IntoIterator`，因此可在 `for` 中自动转为迭代器（也可手动调用 `into_iter()`）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let arr = [1, 2, 3];\n",
    "for v in arr.into_iter() {\n",
    "    println!(\"{}\", v);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 范围 `1..10` 等同理，实现 `IntoIterator` 后就能直接被 `for` 使用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "for i in 1..10 {\n",
    "    println!(\"{}\", i);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 惰性初始化\n",
    "\n",
    "如果你不使用它，那么它将不会发生任何事.\n",
    "\n",
    "确保了创建迭代器不会有任何额外的性能损耗，其中的元素也不会被消耗，只有使用到该迭代器的时候，一切才开始"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let v1 = vec![1, 2, 3];\n",
    "\n",
    "let v1_iter = v1.iter();\n",
    "\n",
    "for val in v1_iter {\n",
    "    println!(\"{}\", val);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## next 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于 `for` 如何遍历迭代器，还有一个问题，它如何取出迭代器中的元素？\n",
    "- 迭代器必须实现 `Iterator` 特征的 `next(&mut self) -> Option<Item>`；`for` 循环正是不断调用 `next` 取值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "pub trait Iterator {\n",
    "    type Item;\n",
    "\n",
    "    fn next(&mut self) -> Option<Self::Item>;\n",
    "\n",
    "    // 省略其余有默认实现的方法\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `next` 返回 `Some(item)` 代表取到元素，`None` 表示遍历结束；顺序遵循迭代器内部排列。\n",
    "- 手动调用 `next` 需要 `mut`，因为状态（当前位置）会被更新；`for` 会自动处理这些细节。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "{\n",
    "    let arr = [1, 2, 3];\n",
    "    let mut arr_iter = arr.into_iter();\n",
    "\n",
    "    assert_eq!(arr_iter.next(), Some(1));\n",
    "    assert_eq!(arr_iter.next(), Some(2));\n",
    "    assert_eq!(arr_iter.next(), Some(3));\n",
    "    assert_eq!(arr_iter.next(), None);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 可用显式循环 + `next` 来“手搓”一个 `for`：不断匹配 `Some`/`None`，效果等同语法糖。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 模拟实现 for 循环\n",
    "\n",
    "let values = vec![1, 2, 3];\n",
    "\n",
    "{\n",
    "    let result = match IntoIterator::into_iter(values) {\n",
    "        mut iter => loop {\n",
    "            match iter.next() {\n",
    "                Some(x) => { println!(\"{}\", x); },\n",
    "                None => break,\n",
    "            }\n",
    "        },\n",
    "    };\n",
    "    result\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## IntoIterator 特征"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**迭代器也能 `into_iter`**：标准库为所有实现 `Iterator` 的类型提供了 `IntoIterator` 实现，因此链式 `into_iter()` 调用依旧返回自身。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "impl<I: Iterator> IntoIterator for I {\n",
    "    type Item = I::Item;\n",
    "    type IntoIter = I;\n",
    "\n",
    "    #[inline]\n",
    "    fn into_iter(self) -> I {\n",
    "        self\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let values = vec![1, 2, 3];\n",
    "\n",
    "    for v in values.into_iter().into_iter().into_iter() {\n",
    "        println!(\"{}\",v)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### into_iter, iter, iter_mut\n",
    "\n",
    "**所有权三兄弟**：\n",
    "\n",
    "- `into_iter()` → 夺走所有权，元素按值移动。\n",
    "- `iter()` → 不可变借用，`next` 给 `&T`。\n",
    "- `iter_mut()` → 可变借用，`next` 给 `&mut T`。\n",
    "\n",
    "**选择要点**：看方法前缀与后缀即可秒懂：`into_` 表明所有权转移，`_mut` 代表可变借用，其余情况是不可变借用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "borrow of moved value: `values`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m borrow of moved value: `values`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_32:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mv\u001b[0m\u001b[38;5;68ma\u001b[0m\u001b[38;5;68ml\u001b[0m\u001b[38;5;68mu\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m        \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m move occurs because `values` has type `Vec<i32>`, which does not implement the `Copy` trait",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;37m│\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m help: you can `clone` the value and consume it, but this might not be your desired behavior: `.clone()`",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;54m│\u001b[0m       ",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `values` moved due to this method call",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m?\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mv\u001b[0m\u001b[38;5;100ma\u001b[0m\u001b[38;5;100ml\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                     \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value borrowed here after move",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: note: `into_iter` takes ownership of the receiver `self`, which moves `values`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// into_iter() —— 夺走所有权\n",
    "\n",
    "let values = vec![1, 2, 3];\n",
    "\n",
    "for v in values.into_iter() {\n",
    "    println!(\"{}\", v);\n",
    "}\n",
    "\n",
    "\n",
    "println!(\"{:?}\", values); // 这里如果尝试使用 `values` 会报错，因为它的所有权已经被 move 走。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// iter() —— 不可变借用\n",
    "\n",
    "{\n",
    "  let values = vec![1, 2, 3];\n",
    "  let _values_iter = values.iter();\n",
    "\n",
    "  println!(\"{:?}\", values);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 2, 3]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// iter_mut() —— 可变借用\n",
    "\n",
    "{\n",
    "  let mut values = vec![1, 2, 3];\n",
    "  let mut values_iter_mut = values.iter_mut();\n",
    "\n",
    "  if let Some(v) = values_iter_mut.next() {\n",
    "      *v = 0;\n",
    "  }\n",
    "\n",
    "  println!(\"{:?}\", values); // [0, 2, 3]\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Iterator 和 IntoIterator 的区别\n",
    "\n",
    "**特征区别**：\n",
    "\n",
    "- `Iterator`：定义“如何逐个产出元素”的协议，需要实现 `next`.\n",
    "- `IntoIterator`：定义“如何把某类型变为迭代器”的协议，提供 `into_iter`/`iter`/`iter_mut`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 消费者与适配器\n",
    "\n",
    "消费者是迭代器上的方法，它会消费掉迭代器中的元素，然后返回其类型的值，这些消费者都有一个共同的特点：在它们的定义中，都依赖 `next` 方法来消费元素，因此这也是为什么迭代器要实现 `Iterator` 特征，而该特征必须要实现 `next` 方法的原因。\n",
    "\n",
    "\n",
    "- **迭代器适配器**：返回新的迭代器（如 `map`, `filter`, `zip`），本身惰性，必须配合消费者才能真正执行。\n",
    "- **典型组合**：`iter() → map() → collect()`：“适配器链”负责变形，最后的消费者收尾并落地为具体集合。\n",
    "- **闭包威力**：适配器常用闭包处理元素，可捕获外部变量，实现灵活的筛选、变换等逻辑。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 消费者适配器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let v1 = vec![1, 2, 3];\n",
    "\n",
    "    let v1_iter = v1.iter();\n",
    "\n",
    "    let total: i32 = v1_iter.sum();\n",
    "\n",
    "    assert_eq!(total, 6);\n",
    "\n",
    "    // v1_iter 是借用了 v1，因此 v1 可以照常使用\n",
    "    println!(\"{:?}\",v1);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **消费者适配器**：内部调用 `next`，会彻底耗尽迭代器并返回一个具体值（如 `sum`, `collect`, `fold`）。调用后原迭代器就没了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "borrow of moved value: `v1_iter`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m borrow of moved value: `v1_iter`",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_39:1:1 \u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m 4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mv\u001b[0m\u001b[38;5;68m1\u001b[0m\u001b[38;5;68m_\u001b[0m\u001b[38;5;68mi\u001b[0m\u001b[38;5;68mt\u001b[0m\u001b[38;5;68me\u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m         \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m            \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m move occurs because `v1_iter` has type `std::slice::Iter<'_, i32>`, which does not implement the `Copy` trait",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;246m 6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                             \u001b[38;5;37m│\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                             \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m\u001b[38;5;37m─\u001b[0m help: you can `clone` the value and consume it, but this might not be your desired behavior: `.clone()`",
      " \u001b[38;5;240m   │\u001b[0m                                \u001b[38;5;54m│\u001b[0m    ",
      " \u001b[38;5;240m   │\u001b[0m                                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `v1_iter` moved due to this method call",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;246m12 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m?\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;100mv\u001b[0m\u001b[38;5;100m1\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100me\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                     \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                        \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value borrowed here after move",
      " \u001b[38;5;240m   │\u001b[0m ",
      " \u001b[38;5;240m   │\u001b[0m \u001b[38;5;115mNote\u001b[0m: note: `std::iter::Iterator::sum` takes ownership of the receiver `self`, which moves `v1_iter`",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "    let v1 = vec![1, 2, 3];\n",
    "\n",
    "    let v1_iter = v1.iter();\n",
    "\n",
    "    let total: i32 = v1_iter.sum();\n",
    "\n",
    "    assert_eq!(total, 6);\n",
    "\n",
    "    println!(\"{:?}\",v1); // v1_iter 是借用了 v1，因此 v1 可以照常使用\n",
    "\n",
    "    println!(\"{:?}\",v1_iter); // 因为 `sum` 拿到了迭代器 `v1_iter` 的所有权\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> moved value（被移动的值）指的是：某个变量的所有权已经被转移走了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn sum<S>(self) -> S // 从 sum 源码中也可以清晰看出，self 类型的方法参数拿走了所有权。\n",
    "    where\n",
    "        Self: Sized,\n",
    "        S: Sum<Self::Item>,\n",
    "    {\n",
    "        Sum::sum(self)\n",
    "    }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 迭代器适配器\n",
    "\n",
    "- **迭代器适配器**：返回新的迭代器（如 `map`, `filter`, `zip`），本身惰性，必须配合消费者才能真正执行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// https://godbolt.org/z/a7vYah5o7\n",
    "{\n",
    "  let v1: Vec<i32> = vec![1, 2, 3];\n",
    "\n",
    "  v1.iter().map(|x| x + 1);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// https://godbolt.org/z/W3ndPahha\n",
    "\n",
    "let v1: Vec<i32> = vec![1, 2, 3];\n",
    "\n",
    "let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); // map 会对迭代器中的每一个值进行一系列操作，然后把该值转换成另外一个新值，该操作是通过闭包 |x| x + 1 来完成\n",
    "\n",
    "assert_eq!(v2, vec![2, 3, 4]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### collect\n",
    "\n",
    "**典型组合**：`iter() → map() → collect()`：“适配器链”负责变形，最后的消费者收尾并落地为具体集合。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\"sunface\": 18, \"sunfei\": 18}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "use std::collections::HashMap;\n",
    "\n",
    "{\n",
    "    let names = [\"sunface\", \"sunfei\"];\n",
    "    let ages = [18, 18];\n",
    "    let folks: HashMap<_, _> = names.into_iter().zip(ages.into_iter()).collect();\n",
    "\n",
    "    println!(\"{:?}\",folks);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`zip` 是一个迭代器适配器，它的作用就是将两个迭代器的内容压缩到一起，形成 `Iterator<Item=(ValueFromA, ValueFromB)>` 这样的新的迭代器，在此处就是形如 `[(name1, age1), (name2, age2)]` 的迭代器。\n",
    "\n",
    "然后再通过 `collect` 将新迭代器中`(K, V)` 形式的值收集成 `HashMap<K, V>`，同样的，这里必须显式声明类型，然后 `HashMap` 内部的 `KV` 类型可以交给编译器去推导，最终编译器会推导出 `HashMap<&str, i32>`，完全正确！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 闭包作为适配器参数\n",
    "\n",
    "- **闭包威力**：适配器常用闭包处理元素，可捕获外部变量，实现灵活的筛选、变换等逻辑。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "struct Shoe {\n",
    "    size: u32,\n",
    "    style: String,\n",
    "}\n",
    "\n",
    "fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {\n",
    "    shoes.into_iter().filter(|s| s.size == shoe_size).collect()\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`filter` 是迭代器适配器，用于对迭代器中的每个值进行过滤。 它使用闭包作为参数，该闭包的参数 `s` 是来自迭代器中的值，然后使用 `s` 跟外部环境中的 `shoe_size` 进行比较，若相等，则在迭代器中保留 `s` 值，若不相等，则从迭代器中剔除 `s` 值，最终通过 `collect` 收集为 `Vec<Shoe>` 类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 实现 Iterator 特征\n",
    "\n",
    "创建自己的迭代器 —— 只要为自定义类型实现 `Iterator` 特征即可\n",
    "\n",
    "- 创建一个计数器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "struct Counter {\n",
    "    count: u32, // 计数器保存的 count 字段是 u32 类型\n",
    "}\n",
    "\n",
    "impl Counter {\n",
    "    fn new() -> Counter {\n",
    "        Counter { count: 0 }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 为计数器实现 `Iterator` 特征\n",
    "\n",
    "> **`next` 是核心**：你只需实现 `next`，其余迭代器方法（`zip`, `map`, `filter`, `skip`, `sum`, `fold` 等）都以默认实现依赖 `next`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "impl Iterator for Counter {\n",
    "    type Item = u32; // 特征的关联类型设置为 u32\n",
    "\n",
    "    fn next(&mut self) -> Option<Self::Item> { // 在 next 方法中，最后返回的是实际上是 Option<u32> 类型\n",
    "        if self.count < 5 { // 每次调用 next 方法，都会让计数器的值加一，然后返回最新的计数值，一旦计数大于 5，就返回 None\n",
    "            self.count += 1;\n",
    "            Some(self.count)\n",
    "        } else {\n",
    "            None\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let mut counter = Counter::new();\n",
    "\n",
    "assert_eq!(counter.next(), Some(1));\n",
    "assert_eq!(counter.next(), Some(2));\n",
    "assert_eq!(counter.next(), Some(3));\n",
    "assert_eq!(counter.next(), Some(4));\n",
    "assert_eq!(counter.next(), Some(5));\n",
    "assert_eq!(counter.next(), None);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 实现 Iterator 特征的其它方法\n",
    "\n",
    "可以看出，实现自己的迭代器非常简单，但是 `Iterator` 特征中，不仅仅是只有 `next` 一个方法，那为什么我们只需要实现它呢？因为其它方法都具有[默认实现](https://course.rs/basic/trait/trait.html#默认实现)，所以无需像 `next` 这样手动去实现，而且这些默认实现的方法其实都是基于 `next` 方法实现的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let sum: u32 = Counter::new()\n",
    "    .zip(Counter::new().skip(1)) // 跳过第一个元素，得到 2, 3, 4, 5\n",
    "    .map(|(a, b)| a * b)\n",
    "    .filter(|x| x % 3 == 0)\n",
    "    .sum();\n",
    "assert_eq!(18, sum);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **链式魔法**：`zip` 合并两个迭代器为 `(a, b)` 元组流；`map` 映射新值；`filter` 筛选；`sum` 等消费者最终收束成结果\n",
    "\n",
    "其中 `zip`，`map`，`filter` 是迭代器适配器：\n",
    "\n",
    "- `zip` 把两个迭代器合并成一个迭代器，新迭代器中，每个元素都是一个元组，由之前两个迭代器的元素组成。例如将**形如** `[1, 2, 3, 4, 5]` 和 `[2, 3, 4, 5]` 的迭代器合并后，新的迭代器形如 `[(1, 2),(2, 3),(3, 4),(4, 5)]`\n",
    "- `map` 是将迭代器中的值经过映射后，转换成新的值[2, 6, 12, 20]\n",
    "- `filter` 对迭代器中的元素进行过滤，若闭包返回 `true` 则保留元素[6, 12]，反之剔除\n",
    "\n",
    "而 `sum` 是消费者适配器，对迭代器中的所有元素求和，最终返回一个 `u32` 值 `18`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### enumerate\n",
    "\n",
    "**`enumerate` 获取索引**：返回 `(index, value)` 的新迭代器，可继续串接其他适配器，实现诸如“隔一个取一个 → 累加”等高级流程。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 获取迭代时的索引\n",
    "\n",
    "let v = vec![1u64, 2, 3, 4, 5, 6];\n",
    "for (i,v) in v.iter().enumerate() {\n",
    "    println!(\"第{}个值是{}\",i,v)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "首先 `v.iter()` 创建迭代器，其次 调用 `Iterator` 特征上的方法 `enumerate`，该方法产生一个新的迭代器，其中每个元素均是元组 `(索引，值)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9\n"
     ]
    }
   ],
   "source": [
    "let v = vec![1u64, 2, 3, 4, 5, 6];\n",
    "let val = v.iter()\n",
    "    .enumerate()\n",
    "    // 每两个元素剔除一个\n",
    "    // [1, 3, 5]\n",
    "    .filter(|&(idx, _)| idx % 2 == 0)\n",
    "    .map(|(_, val)| val)\n",
    "    // 累加 1+3+5 = 9\n",
    "    .fold(0u64, |sum, acm| sum + acm);\n",
    "\n",
    "println!(\"{}\", val);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 迭代器的性能"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [main.rs](./bench_for_iter/src/main.rs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "running 2 tests\n",
       "test bench::bench_for  ... bench:     706,308.27 ns/iter (+/- 64,091.92)\n",
       "test bench::bench_iter ... bench:     702,745.78 ns/iter (+/- 48,173.78)\n",
       "\n",
       "test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured; 0 filtered out; finished in 6.43s\n",
       "\n",
       "    Finished `bench` profile [optimized] target(s) in 0.27s\n",
       "     Running unittests src/lib.rs (target/release/deps/bench_for_iter-3527decf4ade7d5c)\n"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd bench_for_iter && cargo bench"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 学习其它方法"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "Rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
